La educación en nuestro país se ha transformado en un tema de debate, sobretodo en los últimos años, debido a la brecha que existe entre las metodologías de enseñanza impuestas por los colegios. Por otro lado, no todas las personas que terminan su etapa escolar logran entrar a la universidad, y quienes lo logran no necesariamente pueden egresar de su carrera debido a diversos factores. ¿Se puede en la realidad establecer una implicancia entre datos de la educación media y la universitaria de una persona?
Es interesante analizar cuáles son los agentes que podrían influir a la hora de terminar los estudios universitarios, pues las hipótesis no son pocas. Además, si se encuentra una relación directa con los atributos a estudiar, se podría llegar a predecir el tiempo de duración real de la carrera de una persona en específico.
Generalmente se habla del tipo de colegio y notas de enseñanza media como causas importantes del éxito o fracaso al ingresar a la educación superior. ¿Es esto cierto? ¿Realmente estas variables tienen una incidencia? ¿Existen otros atributos involucrados? La hipótesis inicial es que los datos sobre el colegio donde estudió una persona y su rendimiento (por ejemplo, comuna del colegio, NEM, tipo de colegio, nivel sí influyen a la hora de determinar cuánto se demorará realmente en terminar su carrera. Si la hipótesis es cierta, entonces, como se mencionó en la sección anterior, se pueden generar predicciones. La idea general es encontrar los atributos que puedan producir algún resultado respecto al período de estudios de cada persona.
Los datasets utilizados para estudiar todas las preguntas e hipótesis mencionadas anteriormente pertenecen al Ministerio de Educación. En particular, el primer y segundo dataset contienen los datos de todas las personas tituladas en 2015 y 2016: http://datos.mineduc.cl/dashboards/20207/descarga-bases-de-datos-titulados-de-educacion-superior/. Cada tabla está en formato csv y posee 42 columnas. Por otro lado, el tercer y cuarto dataset consisten en la información relativa a las notas de alumnos de enseñanza media entre los años 1990 y 2016 de jóvenes y adultos. Cada tabla tiene 8 columnas y también está en formato csv: http://datos.mineduc.cl/dashboards/20389/descarga-de-base-de-datos-notas-de-ensenanza-media-y-percentil-en-jovenes/.
Ejmplo de los atributos que describen los datos de las personas tituladas son los siguientes:
import pandas as pd
import plotly
import numpy as np
import sys
import seaborn as sns; sns.set(color_codes=True)
from collections import defaultdict
import os
import glob
input_dir = 'Titulados'
encoding = 'ISO-8859-1'
delimiter = ';'
decimal = '.'
def filter_file(input_path):
original = pd.read_csv(input_path, encoding='utf-8', sep=delimiter, decimal=decimal,dtype='unicode')
filtered = original
return filtered
input_paths = glob.glob(os.path.join(input_dir, '*'))
filtered = None
output_path = None
dfs = []
for input_path in input_paths:
print(input_path)
dfs.append(filter_file(input_path))
print ("listo")
dfs[0].head()
dfs[3].head()
En las tablas anteriores se muestran algunos datos para ciertos atributos. Los antecedentes tienen relación principalmente con el lugar de estudio e información básica del alumno titulado. A continuación se muestran los tipos de atributos para cada tabla.
Dado que ambas tablas tienen como llave MRUN del alumno, se puede generar sólo una a partir del cruce de datos, y así poder agregar más atributos a la tabla de titulados. A continuación se muestra lo anteriormente descrito:
#Cambiar a minusculas las columnas para poder hacer merge
dfs[0].columns = [x.lower() for x in dfs[0].columns]
dfs[1].columns=[x.lower() for x in dfs[1].columns]
dfs[2]['cat_periodo']=2015
dfs[3]['cat_periodo']=2016
#Concatenar las tablas de titulados
frames=[dfs[2],dfs[3]]
titulados2=pd.concat(frames,ignore_index=True)
frames2=[dfs[0],dfs[1]]
egresados=pd.concat(frames2,ignore_index=True)
# merge de tabla de egresados y titulados que va a mostrar la intersección por mrun
total=pd.merge(egresados,titulados2, on='mrun', how='inner')
total.head()
Por lo que el tamaño de nuestro Data set queda:
total.shape
mrundup = total.mrun.value_counts()
mrundup[mrundup > 1].head()
A continuación revisamos en detalle algunos mrun repetidos:
total.loc[total['mrun']=='1712224']
total.loc[total['mrun']=='2622180']
De lo anterior se puede deducir que existen algunos mrun que estan repetidos innecesariamente mienstras otros son porque el alumno estudió más de una carrera o hizo un postgrado. Ahora dado que la mayoría de los repetidos son postítulos, la alternativa más sencilla es eliminar las filas que tienen postítulos, ya que esto no es relevante en el análisis (sólo se quiere estudiar la gente que obtuvo un grado académio):
# filtrar todos los que no seas postitulo
total=total.loc[total['nivel_global']!=u'POSTÍTULO']
De acuerdo a nuestra hipótesis se quiere medir los años reales que al alumno le tomó titularse, por lo que se quiere ver si existe incongruencia en la diferencia de año de ingreso a la universidad y año de titulación.
total[[u'año_ing_pri_año']] = total[[u'año_ing_pri_año']].astype(int)
columns=['cat_periodo',u'año_ing_pri_año']
total=total.loc[total['cat_periodo']-total[u'año_ing_pri_año']>0]
Ahora que no se tiene incongruencia entre los años de titulación e ingreso a la carrera se creará la columna años_carrera para que para cada alumno se tenga los años que demoró en obtener el título y la columna duración total en años, pues la actual se encuentra en semestres:
total['anos_carrera']=total['cat_periodo']-total[u'año_ing_pri_año']
total.head()
total[['dur_total_carr']] = total[['dur_total_carr']].astype(int)
total['dur_total_anos']=total['dur_total_carr']/int(2)
total.head()
Si bien hay muchos atributos que son relevantes para este estudio, la dimensión de la tabla resultante no es pequeña, por lo que es probable que no todos los atributos sean imprescindibles. Así, las columnas que se pueden eliminar son las siguientes:
A continuación se presentarán gráficos para ver relaciones entre los datos, outliers, etc. Primero se reemplazarán los valores null por 0 para poder graficar:
total=total.fillna(0)
total[['edad_alu', 'dur_estudio_carr']] = total[['edad_alu', 'dur_estudio_carr']].astype(int)
total[['nem']] = total[['nem']].astype(float)
import matplotlib.pyplot as plt
import pandas
names = ['edad_alu', 'dur_estudio_carr','nem','anos_carrera','dur_total_anos']
filtrado=total.filter(items=names)
filtrado.plot(kind='box', subplots=True, sharex=False, sharey=False,figsize=(20,10))
plt.show()
En la figura anterior (box plot), se muestra que en la edad de los alumnos hay valores extremos como alumnos que tienen edades mayores a 50 y edad 0 ( la cual es falta de información)
A continuación separaremos los datos por código de dependencia del colegio y se compararán con respecto al nem
municipales=total.loc[(total['cod_depe']=='1') | (total['cod_depe']=='2')]
particulares=total.loc[total['cod_depe']=='4']
subvencionados=total.loc[(total['cod_depe']=='3')| (total['cod_depe']=='5')]
subvencionados['nem'].hist(bins=20)
municipales['nem'].hist(bins=20)
particulares['nem'].hist(bins=20)
En el gráfico anterior se ve que los colegios subvencionados y municipales tienen similar nem. Por otro lado, los colegios privados tienen mejor nem que los subvencionados y municipales (entre 60-65).
Luego, se quiere analizar el total de matriculados por género y dependencia:
municipalesHombre=municipales.loc[municipales['gen_alu']=='1']
subvencionadosHombre=subvencionados.loc[subvencionados['gen_alu']=='1']
particularesHombre=particulares.loc[particulares['gen_alu']=='1']
municipalesMujer=municipales.loc[municipales['gen_alu']=='2']
subvencionadosMujer=subvencionados.loc[subvencionados['gen_alu']=='2']
particularesMujer=particulares.loc[particulares['gen_alu']=='2']
listaHombres=[34844,55098,14448]
listaMujeres=[54465,79231,15824]
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
# data to plot
n_groups = 3
means_franka = tuple(listaMujeres)
means_guidoa = tuple(listaHombres)
# create plot
fig, ax = plt.subplots(figsize=(10, 5))
index = np.arange(n_groups)
bar_width = 0.40
opacity = 0.9
rects1 = plt.bar(index, means_franka, bar_width,
alpha=opacity,
color='b',
label=u'Mujeres')
rects2 = plt.bar(index + bar_width, means_guidoa, bar_width,
alpha=opacity,
color='g',
label=u'Hombres')
plt.xlabel(u'Por genero')
plt.ylabel(u'Cantidad de Titulados')
plt.title(u'Cantidad de titulados por genero y dependencia')
plt.xticks(index + bar_width, (u'Municipales',u'Subvencionados',u'Particulares'))
plt.legend()
plt.tight_layout()
plt.show()
Del gráfico se deduce que el número de titulados de colegios subvencionados es significativamente mayor a las otras dependencias y el número de alumnos mujeres es mayor en todas las dependencias.
Dado esto, se decidió comparar porcentajes y comparar por tipo de institución:
centroFormacionTecnica=total.loc[total[u'tipo_inst_2']==u'CENTROS DE FORMACI\xd3N T\xc9CNICA']
universidadprivada=total.loc[total[u'tipo_inst_2']=='UNIVERSIDADES PRIVADAS']
institutoprofesional=total.loc[total[u'tipo_inst_2']=='INSTITUTOS PROFESIONALES']
universidadtradicional=total.loc[total[u'tipo_inst_2']=='UNIVERSIDADES CRUCH']
centroFormacionTecnicamunicipales=centroFormacionTecnica.loc[(centroFormacionTecnica['cod_depe']=='1') | (centroFormacionTecnica['cod_depe']=='2')]
centroFormacionTecnicasubvencionados=centroFormacionTecnica.loc[(centroFormacionTecnica['cod_depe']=='3') | (centroFormacionTecnica['cod_depe']=='5')]
centroFormacionTecnicaparticulares=centroFormacionTecnica.loc[centroFormacionTecnica['cod_depe']=='4']
universidadprivadamunicipales=universidadprivada.loc[(universidadprivada['cod_depe']=='1') | (universidadprivada['cod_depe']=='2')]
universidadprivadasubvencionados=universidadprivada.loc[(universidadprivada['cod_depe']=='3') | (universidadprivada['cod_depe']=='5')]
universidadprivadaprivados=universidadprivada.loc[universidadprivada['cod_depe']=='4']
institutoprofesionalmunicipales=institutoprofesional.loc[(institutoprofesional['cod_depe']=='1') | (institutoprofesional['cod_depe']=='2')]
institutoprofesionalsubvencionados=institutoprofesional.loc[(institutoprofesional['cod_depe']=='3') | (institutoprofesional['cod_depe']=='5')]
institutoprofesionalprivados=institutoprofesional.loc[institutoprofesional['cod_depe']=='4']
universidadtradicionalmunicipales=universidadtradicional.loc[(universidadtradicional['cod_depe']=='1') | (universidadtradicional['cod_depe']=='2')]
universidadtradicionalsubvencionados=universidadtradicional.loc[(universidadtradicional['cod_depe']=='3') | (universidadtradicional['cod_depe']=='5')]
universidadtradicionalprivados=universidadtradicional.loc[universidadtradicional['cod_depe']=='4']
listamunicipales2=[(35379/float(86771))*100,(19081/float(42517))*100,(16198/float(66430))*100,(18651/float(58209))*100]
listasubvencionados=[(48968/float(86771))*100,(22524/float(42517))*100,(33956/float(66430))*100,(28881/float(58209))*100]
listaprivados2=[(2416/float(86771))*100,(908/float(42517))*100,(16273/float(66430))*100,(10675/float(58209))*100]
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
# data to plot
n_groups = 4
means_franka = tuple(listamunicipales2)
means_guidoa = tuple(listasubvencionados)
privados= tuple(listaprivados2)
# create plot
fig, ax = plt.subplots(figsize=(12, 6))
index = np.arange(n_groups)
bar_width = 0.20
opacity = 0.8
rects1 = plt.bar(index, means_franka, bar_width,
alpha=opacity,
color='b',
label=u'Municipales')
rects2 = plt.bar(index + bar_width, means_guidoa, bar_width,
alpha=opacity,
color='g',
label=u'Subvencionados')
rects3 = plt.bar(index + 2*bar_width, privados, bar_width,
alpha=opacity,
color='m',
label=u'Privados')
plt.xlabel(u'Tipo de Institución')
plt.ylabel(u'Porcentaje de titulados')
plt.title(u'Porcentaje de titulados por dependencia y tipo de institución')
plt.xticks(index + bar_width, (u'INSTITUTOS PROFESIONALES',u'CENTROS DE FORMACI\xd3N T\xc9CNICA',u'UNIVERSIDADES PRIVADAS',u'UNIVERSIDADES CRUCH'))
plt.legend()
plt.tight_layout()
plt.savefig('prueba')
plt.show()
En el gráfico se puede ver que el porcentaje de personas tituladas provenientes de colegios particulares en institutos profesinales y centro de formación técnica es mínima. Por otro lado, los centro de formación técnica tienen similar porcentaje de alumnos de colegios municipales y privados.
Finalmente se realizó un parallel coordinates para ver las relaciones entre los atributos de la siguiente forma:
mydict={u'INSTITUTOS PROFESIONALES':1,
u'UNIVERSIDADES PRIVADAS':2,
u'CENTROS DE FORMACI\xd3N T\xc9CNICA':3,
u'UNIVERSIDADES CRUCH':4
}
ans=[]
for key,value in mydict.items():
ans.append([key,value])
tipoInst=pd.DataFrame(ans, columns=['tipo_inst_2','cod_tipo_inst'])
total1=pd.merge(total,tipoInst,on='tipo_inst_2',how='inner')
total2=pd.DataFrame(total1, columns=['tipo_inst_2','cod_tipo_inst'])
import colorlover as cl
import plotly.plotly as py
import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
def configure_plotly_browser_state():
import IPython
display(IPython.core.display.HTML('''
<script src="/static/components/requirejs/require.js"></script>
<script>
requirejs.config({
paths: {
base: '/static/base',
plotly: 'https://cdn.plot.ly/plotly-latest.min.js?noext',
},
});
</script>
'''))
init_notebook_mode(connected=False)
colorscale = [[i,x] for i,x in enumerate(cl.scales['5']['div']['RdYlBu'])]
configure_plotly_browser_state()
total12=total1.sample(n=10000)
total12[['cod_depe']]=total12[['cod_depe']].astype(int)
data = [
go.Parcoords(
line = dict(color = total12['cod_depe'],
showscale=True),
dimensions = list([
dict(range = [18,70],
label = 'Edad', values = total12['edad_alu']),
dict(range = [1990,2016],
label = 'Ano', values = total12[u'año_ing_pri_año']),
dict(range = [4.0,7.0],
label = 'Nem', values = total12['nem']),
dict(tickvals = [1,2,3,4],
ticktext = [u'INSTITUTOS PROFESIONALES',u'UNIVERSIDADES PRIVADAS',u'CENTROS DE FORMACI\xd3N T\xc9CNICA',u'UNIVERSIDADES CRUCH'],
label = 'Tipo Institucion', values = total12['cod_tipo_inst']),
dict(range = [0,13],
label = 'Duracion carreras', values = total12['dur_total_anos']),
])
)
]
layout = go.Layout(
plot_bgcolor = '#E5E5E5',
paper_bgcolor = '#E5E5E5'
)
fig = go.Figure(data = data, layout = layout)
iplot(fig, filename = 'parcoords-basic')
En el gráfico anterior el color esta mapeado al tipo de dependencia ( municipal, subvencionado,etc) y se puede apreciar que la mayoría son de color amarillo (subvencionados) y la mayoría entre 20 y 30 se tituló entre 2005 y 2015. Por otro lado la duración de las carreras parece bordear ente los 2 y 7 años en las instituciones.
Para este hito se partió con filtrar las columnas que creemos relevantes para la hipótesis, a continuación las columnas que elegimos
columns=['rbd','cod_depe','agno_egreso','mrun','nem','percentil','puesto_10','cat_periodo','codigo_unico','gen_alu','edad_alu',u'año_ing_pri_año','nomb_titulo_obtenido','otro_semestre_suspension','tipo_inst_2','nomb_inst','nivel_carrera_2','dur_estudio_carr','dur_total_carr','region_sede','oecd_area','anos_carrera','dur_total_anos']
tablaNueva= pd.DataFrame(total1, columns=columns)
tablaNueva['dur_total_carr'].max()
Para calcular el coeficiente de demora que es cuánto se demora una persona efectivamente en sacar la carrera es:
tablaNueva['coef']=(tablaNueva['anos_carrera']-tablaNueva['dur_total_anos'])
donde anos_carrera es la columna que se creó de cuantos años efectivos esta en la carrera y "dur_total_anos" los años teóricos de la carrera.
tablaNueva['coef'].unique()
Luego se realizó un histograma para ver entre que números estaba el coeficiente:
plt.figure()
tablaNueva['coef'].plot.hist(bins=25)
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
import timeit
Luego se quiso ver como era la distribución del coeficiente según universidad, para así enfocarnos en un grupo específico y evaluar el porque de la demora.
columns=['tipo_inst_2','coef','dur_total_anos']
reducido=pd.DataFrame(tablaNueva, columns=columns)
import matplotlib.pyplot as plt
bins = np.arange(0, 65, 5)
g = sns.FacetGrid(reducido,col='tipo_inst_2',margin_titles=True,height=4,col_order=["INSTITUTOS PROFESIONALES", "UNIVERSIDADES PRIVADAS","UNIVERSIDADES CRUCH","CENTROS DE FORMACIÓN TÉCNICA"])
g = g.map(plt.hist, "coef",bins=20 ,color="m")
g.savefig("graficoMineria.png")
En la visualización anterior se puede apreciar que en los institutos profesionales y centros de formación técnica la gente sale en el tiempo debido, por lo que nuestro estudio se hará en las universidades privadas y las universidades del cruch
Ahora dado que daban resultados "extraños" en el coeficiente como -4, decidimos filtrar las filas tal que el coeficiente sea mayor que -2
reducido=reducido.loc[reducido['coef']>-2]
nuevo=reducido.groupby(['tipo_inst_2']).mean()
Luego se tiene otra visualizacion de donde se encuentra el coeficiente promedio mas alto y el promedio de duración total de la carrera promedio más alto según tipo de institución:
cm = sns.light_palette("red", as_cmap=True)
s = nuevo.style.background_gradient(cmap=cm)
s
El resultado fue que las universidades del cruch tienen en promedio mayor coeficiente y además sus carreras duran más
tablaNueva=tablaNueva.loc[tablaNueva['coef']>=-1]
mydictionare = {
-0.5:'A',
0.5:'B',
-1:'A',
0:'A',
1:'B',
2.5:'B',
1.5:'B',
2:'B',
3.5:'B',
4.5:'B',
7:'B',
3:'B',
4:'B',
5:'B',
5.5:'B',
6.5:'B',
6:'B',
7.5:'B',
8:'B',
8.5:'B',
12:'B',
8.5:'B',
12:'B',
11.5:'B',
9.5:'B',
15:'B',
9:'B',
14.5:'B',
10:'B',
17.5:'B',
13:'B',
16:'B',
11:'B',
12.5:'B',
14:'B',
17:'B'
}
ans=[]
for key,value in mydictionare.items():
ans.append([key,value])
clase=pd.DataFrame(ans, columns=['coef','clase'])
tablaNuevaClases=pd.merge(tablaNueva,clase,on=['coef'],how='inner')
reduced_data = tablaNuevaClases
import seaborn as sns
sns.set(style="ticks", color_codes=True)
g = sns.pairplot(reduced_data, vars=['nem', 'dur_total_anos', 'coef', 'anos_carrera'])
plt.show()
Para poder aplicar las técnicas de clasificación, se generó una tabla reducida donde se eliminaron las variables que se consideraba que tenían menos correlación con las clases. Así, sólo quedaron el género del alumno y la duración total de años de la carrera. De esta tabla se creó una muestra de 80000 filas debido a la demora al procesar los datos. Finalmente se mapearon las clases a tipos numéricos.
tablaUniversidades=tablaNuevaClases.loc[(tablaNuevaClases['tipo_inst_2']=='UNIVERSIDADES PRIVADAS') | (tablaNuevaClases['tipo_inst_2']=='UNIVERSIDADES CRUCH')]
columns=['gen_alu', 'dur_total_anos','clase']
tablaUniversidades[['gen_alu']] = tablaUniversidades[['gen_alu']].astype(int)
tablaUniversidades=pd.DataFrame(tablaUniversidades,columns=columns)
tablaPrueba=tablaUniversidades.sample(n=80000)
tablaPrueba['clase'] = tablaPrueba['clase'].map({'A':1, 'B':3})
tablaPrueba = tablaPrueba.dropna()
array = tablaPrueba.values
Finalmente aquí se comienza a aplicar clasificación, partiendo con Árbol de Decisión. Los datos de entrenamiento corresponden al 70% de la muestra. Además, se evaluó el desempeño mediante la tabla de métricas y se contaron la cantidad de clases (a pesar de ser una selección aleatoria de la muestra siempre daba una proporción similar)
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score, recall_score, precision_score
from sklearn.tree import DecisionTreeClassifier
X = array[:,0:2]
y= array[:,2]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.30,train_size=0.70, stratify=y)
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
predictions=clf.predict(X_test)
from sklearn.metrics import accuracy_score, classification_report
print(classification_report(y_test,predictions))
accuracy_score(y_test, predictions)
tablaUniversidades['clase'].value_counts()
Con su respectiva matriz de confución
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, predictions)
plt.matshow(cm)
plt.colorbar()
plt.ylabel('True label')
plt.xlabel('Predicted label')
from sklearn import metrics, model_selection
print("\nPREDICTIONS******")
predictions = model_selection.cross_val_predict(clf, X_test, y_test, cv=10) ## cv es la cantidad de folds
print("Accuracy:", metrics.accuracy_score(y_test, predictions))
print("Metricas:")
print(metrics.classification_report(y_test, predictions))
# Para cargar KNN
from sklearn.neighbors import KNeighborsClassifier
K = 5 # numero de vecinos
knn = KNeighborsClassifier(n_neighbors=K)
## AGREGUE CODIGO PREGUNTA 5.2
knn.fit(X, y)
y_pred2 = knn.predict(X_test)
print("Accuracy:", metrics.accuracy_score(y_test,y_pred2))
print(metrics.classification_report(y_test, y_pred2))
from sklearn.naive_bayes import GaussianNB # naive bayes
clf = GaussianNB()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.30,train_size=0.70, stratify=y)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
print("Accuracy:", metrics.accuracy_score(y_test, predictions))
print(metrics.classification_report(y_test, predictions))
Accuracy: 0.5862083333333333
Para este hito, decidimos agregar atributos a nuestra base de datos. Dado que que poseemos el rbd del colegio se pudo obtener la región y la comuna de este. Con datos de http://junaebabierta.junaeb.cl/ , se pudo obtener el índice de vulnerabilidad del colegio. Se filtraron alumnos que estudiaron en una universidad del cruch (cantidad de alumnos que terminaron su carrera a tiempo y los que no, pues en este caso las clases estan balanceadas).
input_dir = 'hito3'
encoding = 'ISO-8859-1'
delimiter = ','
decimal = '.'
def filter_file(input_path):
original = pd.read_csv(input_path, encoding=encoding, sep=delimiter, decimal=decimal,dtype='unicode')
filtered = original
return filtered
input_paths = glob.glob(os.path.join(input_dir, '*'))
filtered = None
output_path = None
dfs = []
for input_path in input_paths:
print(input_path)
dfs.append(filter_file(input_path))
print ("listo")
total = dfs[0]
tablaNueva=total
ans=[]
for key,value in mydictionare.items():
ans.append([key,value])
clase=pd.DataFrame(ans, columns=['coef','clase'])
tablaNueva[['coef']] = tablaNueva[['coef']].astype(float)
tablaNuevaClases=pd.merge(tablaNueva,clase,on=['coef'],how='inner')
tablaNuevaClases[['cod_reg_rbd']] = tablaNuevaClases[['cod_reg_rbd']].astype(int)
tablaNuevaClases[['% ive-sinae media 2016']] = tablaNuevaClases[['% ive-sinae media 2016']].astype(float)
tablaUniversidades=tablaNuevaClases.loc[(tablaNuevaClases['tipo_inst_2']=='UNIVERSIDADES PRIVADAS') | (tablaNuevaClases['tipo_inst_2']=='UNIVERSIDADES CRUCH')]
columns=['gen_alu', 'dur_total_anos', 'cod_reg_rbd','clase']
tablaUniversidades[['gen_alu']] = tablaUniversidades[['gen_alu']].astype(int)
tablaUniversidades[['dur_total_anos']] = tablaUniversidades[['dur_total_anos']].astype(float)
tablaUniversidades=pd.DataFrame(tablaUniversidades,columns=columns)
tablaPrueba=tablaUniversidades.sample(n=50000)
tablaPrueba['clase'] = tablaPrueba['clase'].map({'A':1, 'B':3})
tablaPrueba = tablaPrueba.dropna()
array = tablaPrueba.values
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score, recall_score, precision_score
from sklearn.tree import DecisionTreeClassifier
X = array[:,0:3]
y= array[:,3]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.30,train_size=0.70, stratify=y)
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
predictions=clf.predict(X_test)
from sklearn.metrics import accuracy_score, classification_report
print(classification_report(y_test,predictions))
accuracy_score(y_test, predictions)
tablaUniversidades['clase'].value_counts()
from sklearn import metrics, model_selection
print("\nPREDICTIONS******")
predictions = model_selection.cross_val_predict(clf, X_test, y_test, cv=10) ## cv es la cantidad de folds
print("Accuracy:", metrics.accuracy_score(y_test, predictions))
print("Metricas:")
print(metrics.classification_report(y_test, predictions))
# Para cargar KNN
from sklearn.neighbors import KNeighborsClassifier
K = 5 # numero de vecinos
knn = KNeighborsClassifier(n_neighbors=K)
## AGREGUE CODIGO PREGUNTA 5.2
knn.fit(X, y)
y_pred2 = knn.predict(X_test)
print("Accuracy:", metrics.accuracy_score(y_test,y_pred2))
print(metrics.classification_report(y_test, y_pred2))
from sklearn.naive_bayes import GaussianNB # naive bayes
clf = GaussianNB()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.30,train_size=0.70, stratify=y)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
print("Accuracy:", metrics.accuracy_score(y_test, predictions))
print(metrics.classification_report(y_test, predictions))
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.30,train_size=0.70, stratify=y)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
print("Accuracy:", metrics.accuracy_score(y_test, predictions))
print(metrics.classification_report(y_test, predictions))
cm = confusion_matrix(y_test, predictions)
plt.matshow(cm)
plt.colorbar()
plt.ylabel('True label')
plt.xlabel('Predicted label')
Nuestro clasificador no tuvo buenos resultados bajo ningún método solo mejoró un 1% (60% aprox) el rendimiento con respecto al hito 2, por lo que se intentó otra técnica de Minería de Datos.
Se buscaron reglas de asociación en el dataset, para así obtener diferencias entre los alumnos que terminaron a tiempo y los que no. Primero se categorizaron las columnas a utilizar y luego se dividió el dataset entre los que terminaron a tiempo y los que no, para hacer un estudio comparativo. Se escogieron las columnas: cod_depe, rango_nem, gen_alu, oecd_area, rango_edad, cod_reg e índice para hacer los experimentos y se utilizo el algorimto apriori.
En este experimento se consideraron a los alumnos que salieron a tiempo y solo se consideraon el rango_nem, gen_alu, oecd_are, rango_edad y cod_reg y se utilizó el algoritmo apriori con un confidence mínimo del 0,03 y support mínimo del 0,01 :
En las reglas anteriores podemos notar un alto confidence y lift lo que demuestra que los itemsets estan altamente relacionados. Por otro lado, notamos que el support da bajo lo que puede ser resultado de que el dataset es grande (26 mil registros). Luego se ve que las reglas tienen que ver con el genero del alumno, por ejemplo: cod_depe=4 (colegio privado) y educación estan relacionados con gen_alu 2 que es ser mujer.
Luego se hizo lo mismo para el grupo de alumnos con coeficiente mayor a cero y se obtuvo:
De lo anterior se concluye que no hay diferencia en las reglas del primer y segundo grupo
En este caso quitamos el rango_nem y agregamos el indice de vulnerabilidad del colegio y se obtiene:
En este experimento mejoró considerablemente el lift y se obtuvieron reglas sobre las regiones, por ejemplo: La región de antofagasta e indice de vulnerabilidad medio esta altamente relacionado con el cod_depe 1 que es colegio municipal.
A continuación graficamos para observar si se reflejan las reglas de asociación:
En este gráfico se puede observar que efectivamente las mujeres estudian más carreras de educación y los hombres de ingeniería.
En ese gráfico se muestra que la región de Arica y Parinacota tiene un coef de demora considerablemente mayor que la otras regiones los que nos dice que podemos examinar el data set de forma más especificas para hacer nuestro estudio
El último experimento consistió en filtrar los colegios municipales tradicionales (Carmela Carvajal e Instituto nacional) y alumnos de colegios privados de excelencia (Nido de aguila, colegio Internacional Alba, etc)
y se obtuvieron los siguientes resultados respectivamente:
Del trabajo realizado podemos obtener las siguientes conlusiones:
Considerar un universo más amplio y con menos sesgo, con clases más distinguibles entre sí, por ejemplo: personas tituladas y no tituladas y predecir quiénes tienes más posibilidades de desertar.
Por otro lado, se puede reducir el universo a estudiar, es decir, estudiar por carrera o región el coeficiente de demora pues así se pueden notar diferencias más marcadas.